﻿using ajayumi.develop.win32.Transport.WCF.Services;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ServiceModel;
using System.Text.RegularExpressions;
using System.Windows.Forms;

namespace ajayumi.develop.win32.Transport.Client.WinForm.Controls
{
    public partial class UcDriveTree : UserControl
    {
        private readonly DriveServiceClient m_Client = null;

        #region property

        /// <summary>
        /// 获取当前选择的路径
        /// </summary>
        public string Path
        {
            get
            {
                TreeNode node = this.tvDrive.SelectedNode;
                string path = string.Empty;
                if (node != null)
                {
                    path = Regex.Match(node.FullPath, @"[^\\]+:\\.*", RegexOptions.IgnoreCase).Value;
                    path = path.Replace("\\\\", "\\");
                }

                return path;
            }
        }

        /// <summary>
        /// 是否为目录节点
        /// </summary>
        public bool IsDirectoryNode
        {
            get
            {
                bool result = false;

                TreeNode node = this.tvDrive.SelectedNode;
                if (node != null)
                {
                    result = (node.Nodes.Count > 0);
                }

                return result;
            }
        }

        public List<FilePathInfo> DriveNodeList
        {
            get
            {
                List<FilePathInfo> lst = new List<FilePathInfo>();
                string rootPath = this.Path;
                try
                {
                    string[] files = this.m_Client.GetFiles(rootPath, true);
                    foreach (string item in files)
                    {
                        lst.Add(new FilePathInfo()
                        {
                            RootPath = rootPath,
                            RelativePath = item.Replace(rootPath, string.Empty).TrimStart('\\')
                        });
                    }
                }
                catch (FaultException ex)
                {
                    this.m_Client.Abort();
                    MessageBox.Show("在与服务器通信时发生异常，请联系计算机管理员处理该错误。\r\n" + ex.Message);
                }
                catch (TimeoutException ex)
                {
                    this.m_Client.Abort();
                    MessageBox.Show("在与服务器通信时发生异常，请联系计算机管理员处理该错误。\r\n" + ex.Message);
                }
                catch (Exception ex)
                {
                    this.m_Client.Abort();
                    MessageBox.Show(ex.Message);
                }
              

                return lst;
            }
        }

        [Browsable(true)]
        [DefaultValue(false)]
        public bool HasFile { get; set; }

        #endregion

        public UcDriveTree()
        {
            InitializeComponent();
            m_Client = new DriveServiceClient();
        }

        #region method

        /// <summary>
        /// 获取目录列表
        /// </summary>
        /// <param name="node"></param>
        /// <param name="dir"></param>
        private void GetListDirectory(TreeNode node, string dir)
        {
            this.OnBeginLoad(null);

            try
            {
                string[] result = m_Client.GetDirectories(dir, this.HasFile);
                this.FillNodes(node, GenerateNodes(result));
            }
            catch (FaultException ex)
            {
                this.m_Client.Abort();
                MessageBox.Show("在与服务器通信时发生异常，请联系计算机管理员处理该错误。\r\n"+ex.Message);
            }
            catch (TimeoutException ex)
            {
                this.m_Client.Abort();
                MessageBox.Show("在与服务器通信时发生异常，请联系计算机管理员处理该错误。\r\n" + ex.Message);
            }
            catch (Exception ex)
            {
                this.m_Client.Abort();
                MessageBox.Show(ex.Message);
            }
        }

        /// <summary>
        /// 获取目录列表回调方法
        /// </summary>
        /// <param name="ar"></param>
        private void GetListDirectoryCallback(IAsyncResult ar)
        {
            Action<TreeNode, string> action = ar.AsyncState as Action<TreeNode, string>;
            action.EndInvoke(ar);

            this.OnLoadCompleted(new AsyncCompletedEventArgs(null, false, this));
        }

        /// <summary>
        /// 刷新目录树，在窗体OnLoad之后调用
        /// </summary>
        public void AsyncLoad()
        {
            this.tvDrive.Invoke(new Action(this.tvDrive.Nodes.Clear));

            TreeNode rootNode = new TreeNode() { Text = "我的电脑" };
            this.tvDrive.BeginInvoke(new Action<TreeNode[]>(this.tvDrive.Nodes.AddRange), new object[] { new TreeNode[] { rootNode } });

            Action<TreeNode, string> action = new Action<TreeNode, string>(this.GetListDirectory);
            action.BeginInvoke(rootNode, string.Empty, new AsyncCallback(this.GetListDirectoryCallback), action);
        }

        /// <summary>
        /// 插入节点
        /// </summary>
        /// <param name="folderName">节点文本</param>
        public void InsertNode(string folderName)
        {
            TreeNode node = this.tvDrive.SelectedNode;
            if (node == null) return;

            TreeNode newNode = new TreeNode() { Text = folderName };
            node.Nodes.Insert(node.Nodes.Count, newNode);
        }


        private TreeNode[] GenerateNodes(string[] strs)
        {
            int len = strs.Length;
            TreeNode[] nodes = new TreeNode[len];
            for (int i = 0; i < len; i++)
            {
                string text = strs[i];
                if (text.EndsWith(":\\"))
                { }
                else
                { text = Regex.Match(text, @"[^\\]+$").Value; }
                nodes[i] = new TreeNode() { Text = text };
            }

            return nodes;
        }

        /// <summary>
        /// 填充节点
        /// </summary>
        /// <param name="parentNode"></param>
        /// <param name="childNode"></param>
        private void FillNodes(TreeNode parentNode, TreeNode[] childNode)
        {
            this.tvDrive.BeginInvoke(new Action<TreeNode[]>(parentNode.Nodes.AddRange), new object[] { childNode });
        }

        #endregion


        private void SetEnable(TreeView tv, bool value)
        {
            if (tv.InvokeRequired)
            { tv.Invoke(new Action<TreeView, bool>(SetEnable), new object[] { tv, value }); }
            else
            { tv.Enabled = value; }
        }

        #region event

        /// <summary>
        /// 开始加载节点事件
        /// </summary>
        public event EventHandler BeginLoad;
        protected virtual void OnBeginLoad(EventArgs e)
        {
            if (BeginLoad != null)
            {
                this.SetEnable(this.tvDrive, false);
                BeginLoad(this, e);
            }
        }

        /// <summary>
        /// 加载节点完毕事件
        /// </summary>
        public event AsyncCompletedEventHandler LoadCompleted;
        protected virtual void OnLoadCompleted(AsyncCompletedEventArgs e)
        {
            if (LoadCompleted != null)
            {
                this.SetEnable(this.tvDrive, true);
                LoadCompleted(this, e);
            }
        }


        private void tvDrive_BeforeExpand(object sender, TreeViewCancelEventArgs e)
        {
            foreach (TreeNode item in e.Node.Nodes)
            {
                this.tvDrive.Invoke(new Action(item.Nodes.Clear));

                string parentDir = Regex.Match(item.FullPath, @"[^\\]+:\\.*", RegexOptions.IgnoreCase).Value;
                Action<TreeNode, string> action = new Action<TreeNode, string>(this.GetListDirectory);
                action.BeginInvoke(item, parentDir, new AsyncCallback(this.GetListDirectoryCallback), action);
            }
        }

        private void tvDrive_AfterCollapse(object sender, TreeViewEventArgs e)
        {
            e.Node.Collapse();
        }

        #endregion

    }
}
